package cn.fz.redisdemo01.service;

import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.stereotype.Service;

import java.util.concurrent.TimeUnit;

/**
 * 3. 使用 Redisson 实现分布式锁
 * 通过 RedissonClient，我们可以使用分布式锁功能。下面是一个简单的示例，展示如何使用 Redisson 实现分布式锁。
 * 5. 为什么使用Redisson分布式锁
 * 使用 Redisson 实现的分布式锁相对于直接使用 Redis 的分布式锁，具有一些显著的优势，尤其是在功能完善性、开发便捷性以及可扩展性方面。以下是 Redisson 实现的分布式锁相对于手动实现 Redis 分布式锁的几个主要优势：
 * 优势	        Redisson 实现分布式锁	                手动使用 Redis  实现分布式锁
 * 锁机制支持	    可重入锁、公平锁、读写锁等丰富的锁机制	需要手动实现
 * 锁续期机制	    自动续期，防止锁超时失效	            需要手动续期
 * 操作原子性	    内置保证	                            需要 Lua 脚本保障原子性
 * 易用性	    API 简单，易于使用和维护	            需要手动编写命令逻辑
 * 部署架构支持	支持单点、哨兵、集群模式	            需要手动处理高可用
 * 高级功能	    异步、分布式对象、反压支持	            需要手动封装
 * 异步和同步支持	完善的异步和反应式支持	                需要手动编写异步代码
 * 6. 常见问题
 * 死锁问题：如果业务逻辑执行时间超过锁的自动释放时间，会导致锁自动释放，其他线程可能会获取锁，造成数据不一致问题。
 * 为避免这种情况，可以设置足够长的 leaseTime，或者在业务逻辑完成时手动释放锁。
 * 锁竞争激烈：在高并发场景下，多个线程同时竞争锁，可能会导致部分线程长时间无法获取锁。可以通过优化锁的粒度来减少锁的竞争。
 * 7. 总结
 * 通过 Spring Boot 3 和 Redisson 的结合，你可以轻松实现分布式锁的功能，确保在分布式系统中关键任务的正确执行。
 * Redisson 提供了多种锁的实现，如公平锁、读写锁、可重入锁等，能够满足不同的业务需求。
 */
@Service
public class LockService {
    private final RedissonClient redissonClient;

    public LockService(RedissonClient redissonClient) {
        this.redissonClient = redissonClient;
    }

    /**
     * 详细说明
     *
     * RLock：这是 Redisson 提供的分布式锁对象。通过 RedissonClient.getLock() 方法可以获取到一个分布式锁。
     *
     * tryLock(long waitTime, long leaseTime, TimeUnit unit)：此方法尝试获取锁，其中：
     *
     * waitTime 是最大等待时间，表示在该时间内如果未获取到锁则放弃。
     * leaseTime 是锁的自动释放时间，避免因为业务逻辑异常导致锁无法释放。
     * unlock()：业务逻辑执行完后需要手动释放锁，否则其他线程将无法获取锁。
     */
    public void doSomethingWithLock() {
        // 获取锁对象
        RLock lock = redissonClient.getLock("myLock");

        try {
            // 尝试获取锁，等待时间 100ms，锁定时间 10秒
            if (lock.tryLock(100, 10, TimeUnit.SECONDS)){
                try {
                    // 获取锁成功，执行业务逻辑 加锁成功，执行业务逻辑
                    System.out.println("锁定成功，正在执行关键任务...");
                    Thread.sleep(5000);  // 模拟任务执行
                } finally {
                    // 释放锁
                    lock.unlock();
                    System.out.println("任务完成，已释放锁");
                }
            }else {
                System.out.println("无法获取锁，其他线程正在执行该任务");
            }
        } catch (InterruptedException e) {
            System.out.println(e.getMessage());
            // throw new RuntimeException(e);
        }
    }
}
